package com.hzgj.bcl.soa.registry;

import com.hzgj.bcl.soa.config.ReferenceDef;
import com.hzgj.bcl.soa.config.RegistryDef;
import com.hzgj.bcl.soa.config.ServerDef;
import com.hzgj.bcl.soa.config.ServiceDef;
import com.hzgj.bcl.util.jmx.annotation.MBean;
import com.hzgj.bcl.util.jmx.annotation.ManagedOperation;
import com.hzgj.bcl.util.lang.StrKit;

import java.util.List;
import java.util.stream.Collectors;

/**
 * Created by dell on 2015/3/26.
 */
@MBean(description = "registry service")
public class RegistryService {

    private RegistryDef registryDef;
    private RegistryContext registryContext = new RegistryContext();

    private ProviderRegistryService providerRegistryService;

    public RegistryService(RegistryDef registryDef) {
        this.registryDef = registryDef;
        providerRegistryService = new ProviderRegistryService(this);
    }

    @ManagedOperation(description = "up or down service registry")
    public RegistryUpdater.Result upOrDownService(String service, String ipAndPort, boolean down) {
        return providerRegistryService.upOrDownService(service, ipAndPort, down);
    }

    @ManagedOperation(description = "update service properties")
    public RegistryUpdater.Result updateServices(List<ServiceDef.Attr> services) {
        return providerRegistryService.updateServices(services);
    }

    public void handleRegService(final RegistryContext.ServerRegisterModel serverRegisterModel, int period, boolean pull) {
        providerRegistryService.handleRegService(serverRegisterModel, period, pull);
    }

    public void subscribeServices(NotifyListener notifyListener, ReferenceDef... services) {
        getRegistry().subscribe(notifyListener, services);
    }

    public void unSubscribeServices(ReferenceDef... services) {
        getRegistry().unSubscribe(services);
    }

    public List<ServerDef> look(ReferenceDef referenceDef) {
        ServiceDef serviceDef = lookService(referenceDef);
        return serviceDef.getAttrs().stream().map(attr -> attr.getServerDef()).collect(Collectors.toList());
    }

    public ServiceDef lookService(ReferenceDef referenceDef) {
        ServiceDef serviceDef = lookServiceByName(referenceDef.getService());
        if (serviceDef == null) {
            throw new ServiceNotExistException("No provider available for the service " + referenceDef.getService() + "[version=" + referenceDef.getVersion()
                    + ",group=" + referenceDef.getGroup() + "] from registry " +
                    registryDef.getProtocol() + "://" + registryDef.getAddress() + ". Please check if the providers have been started and registered.");
        }

        ServiceDef result = new ServiceDef();
        result.setName(referenceDef.getService());
        if (StrKit.isBlank(referenceDef.getVersion()) && StrKit.isBlank(referenceDef.getGroup())) {
            for (ServiceDef.Attr attr : serviceDef.getAttrs()) {
                if (StrKit.isBlank(attr.getGroup()) && StrKit.isBlank(attr.getVersion())) {
                    result.getAttrs().add(attr);
                }
            }
        } else if (!StrKit.isBlank(referenceDef.getVersion()) && !StrKit.isBlank(referenceDef.getGroup())) {
            for (ServiceDef.Attr attr : serviceDef.getAttrs()) {
                if (referenceDef.getVersion().equals(attr.getVersion()) && referenceDef.getGroup().equals(attr.getGroup())) {
                    result.getAttrs().add(attr);
                }
            }
        } else if (!StrKit.isBlank(referenceDef.getVersion()) && StrKit.isBlank(referenceDef.getGroup())) {
            for (ServiceDef.Attr attr : serviceDef.getAttrs()) {
                if (referenceDef.getVersion().equals(attr.getVersion())) {
                    result.getAttrs().add(attr);
                }
            }
        } else {
            for (ServiceDef.Attr attr : serviceDef.getAttrs()) {
                if (referenceDef.getGroup().equals(attr.getGroup())) {
                    result.getAttrs().add(attr);
                }
            }
        }
        return result;
    }


    public ServiceDef lookServiceByName(String name) {
        return getRegistry().lookupService(name);
    }

    public Registry getRegistry() {
        return registryContext.lookupRegistry(registryDef);
    }

    public RegistryUpdater getUpdater() {
        return registryContext.lookupRegistryUpdater(registryDef);
    }
}
